/**
 * Copyright . (c) 2015, http://www.wuleyou.com/ All Rights Reserved.
 * 
 */

package com.idealighter.game.games.shuihu.manager;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;

import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Table;
import com.google.inject.Inject;
import com.google.inject.Singleton;

import com.idealighter.game.core.common.Game;
import com.idealighter.game.core.tuple.Pair;
import com.idealighter.game.core.tuple.Triplet;
import com.idealighter.game.dictionary.dic.ShuihuBonusIconDic;
import com.idealighter.game.dictionary.dic.ShuihuBonusInnerCfgDic;
import com.idealighter.game.dictionary.dic.ShuihuBonusNumCfgDic;
import com.idealighter.game.dictionary.dic.ShuihuBonusOuterKickOutDic;
import com.idealighter.game.dictionary.dic.ShuihuIconDic;
import com.idealighter.game.dictionary.domain.ShuihuBonusIconDomain;
import com.idealighter.game.dictionary.domain.ShuihuBonusInnerCfgDomain;
import com.idealighter.game.dictionary.domain.ShuihuBonusOuterKickOutDomain;
import com.idealighter.game.dictionary.domain.ShuihuIconDomain;
import com.idealighter.game.games.shuihu.common.BonusInnerCfgTypeConstant;
import com.idealighter.game.games.shuihu.common.RewardCalculator;
import com.idealighter.game.games.shuihu.common.ShuiHuReward;
import com.idealighter.game.games.shuihu.struct.ShuiHuDifficulty;
import com.idealighter.game.games.shuihu.struct.ShuiHuSeat;
import com.idealighter.game.message.core.ResMessage;
import com.idealighter.game.prizepool.manager.PlayerPrizePoolMgrScript;
import com.idealighter.game.prizepool.manager.RoomPrizePoolMgrScript;
import com.idealighter.game.prizepool.struct.control.ShuiHuControl;
import com.idealighter.game.prizepool.struct.player.PlayerPrizePool;
import com.idealighter.game.prizepool.struct.room.ControlStrategy;
import com.idealighter.game.prizepool.struct.room.RoomPrizePool;
import com.idealighter.utils.code.RandCodeUtil;

import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 水浒控制脚本 .
 * 
 * @date 2015年11月9日 下午4:35:37
 *
 */
@Singleton
public class ShuiHuControlScript {

  private static final TypeReference<ShuiHuControl> SHUIHU_CONTROL_TYPE =
      new TypeReference<ShuiHuControl>() {};

  // 小玛丽退出图标
  public static final int BONUS_EXIT_ICON = 9;
  // 图标行数
  public static final int ICON_ROWS = 3;
  // 图标列数
  public static final int ICON_COLUMNS = 5;

  @Inject
  private ShuiHuMsgMgr msgMgr;
  @Inject
  private ShuiHuMgr shuiHuMgr;
  @Inject
  private ShuihuIconDic iconDic;
  @Inject
  private ShuihuBonusIconDic bonusIconDic;
  @Inject
  private ShuihuBonusNumCfgDic shuihuBonusNumCfgDic;
  @Inject
  private ShuihuBonusOuterKickOutDic shuihuBonusOuterKickOutDic;
  @Inject
  private ShuihuBonusInnerCfgDic shuihuBonusInnerCfgDic;

  @Inject
  private PlayerPrizePoolMgrScript playerPrizePoolMgr;
  @Inject
  private RoomPrizePoolMgrScript roomPrizePoolMgr;


  /**
   * 控制水浒图标.
   * 
   * @param seat 座位.
   * @return 水浒得奖.
   */
  public ShuiHuReward randomShuiHuIcons(ShuiHuSeat seat) {
    /*
     * 个人奖池控制 .
     */
    PlayerPrizePool prizePool =
        playerPrizePoolMgr.prizePool(seat.getPlayerId(), Game.SHUI_HU_ZHUAN);
    if (!seat.isRobot() && prizePool != null && prizePool.getPrize().get() != 0) {
      return randomPlayerPrizePoolIcons(seat, prizePool);
    }

    /*
     * 房间奖池控制 .
     */
    long roomId = seat.getTable().getRoom().getId();
    RoomPrizePool roomPrizePool =
        roomPrizePoolMgr.roomPrizePool(seat.getPlayerId(), Game.SHUI_HU_ZHUAN, roomId);
    if (!seat.isRobot() && roomPrizePool != null) {
      return randomRoomPrizePoolIcons(seat, roomPrizePool);
    }

    // 正常概率图标
    return randomNormalShuiHuIcons(seat);
  }

  /**
   * 随机水浒图标.
   * 
   * @param seat 座位
   */
  public ShuiHuReward randomNormalShuiHuIcons(ShuiHuSeat seat) {
    Table<Integer, Integer, Integer> icons = seat.getIcons();

    for (int i = 0; i < ICON_ROWS; i++) {
      for (int j = 0; j < ICON_COLUMNS; j++) {
        // 合计权重
        int totalWeight = iconDic.getTotalWeight();
        // 随机数
        int rand = RandCodeUtil.random(totalWeight);
        int sum = 0;
        int icon = 0;

        for (ShuihuIconDomain iconDomain : iconDic.list()) {
          sum += iconDomain.getWeight();
          if (rand < sum) {
            icon = iconDomain.getId();
            break;
          }
        }

        icons.put(i, j, icon);
      }
    }

    return RewardCalculator.calculate(seat.getIcons(), shuihuBonusNumCfgDic.map(), seat.getLine(),
        seat.getBet());
  }

  /**
   * 随机难度图标.
   * 
   * @param seat 座位
   * @param difficulty 难度
   * @return 奖励信息
   */
  private ShuiHuReward randomDiffcultyIcons(ShuiHuSeat seat, ShuiHuDifficulty difficulty) {
    Table<Integer, Integer, Integer> icons = seat.getIcons();
    // 合计权重
    int totalWeight = difficulty.totalWeight();

    for (int i = 0; i < ICON_ROWS; i++) {
      for (int j = 0; j < ICON_COLUMNS; j++) {
        // 随机数
        int rand = RandCodeUtil.random(totalWeight);
        int sum = 0;
        int icon = 0;
        int[] weights = difficulty.getWeights();
        for (int k = 0; k < weights.length; k++) {
          int weight = weights[k];
          sum += weight;
          if (rand < sum) {
            icon = k + 1;
            break;
          }
        }

        icons.put(i, j, icon);
      }
    }

    return RewardCalculator.calculate(seat.getIcons(), shuihuBonusNumCfgDic.map(), seat.getLine(),
        seat.getBet());
  }

  /**
   * 随机个人奖池水浒图标.
   * 
   * @param seat 座位信息
   * @param prizePool 奖池信息
   * @return 奖励信息
   */
  private ShuiHuReward randomPlayerPrizePoolIcons(ShuiHuSeat seat, PlayerPrizePool prizePool) {
    ShuiHuControl shuiHuControl = JSON.parseObject(prizePool.getControl(), SHUIHU_CONTROL_TYPE);
    ShuiHuDifficulty shuiHuDifficulty = ShuiHuDifficulty.get(shuiHuControl.getDifficulty());

    // 图标奖励
    ShuiHuReward shuiHuReward = randomDiffcultyIcons(seat, shuiHuDifficulty);
    long prize = prizePool.getPrize().get();
    long winGold = shuiHuMgr.convertGold(seat.getTable().getRoom().getRoomDomain(),
        shuiHuReward.getWin() - seat.getLine() * seat.getBet());

    if (prize > 0) {
      prize = prize - winGold;
      prize = prize < 0 ? 0 : prize;
    } else if (prize < 0) {
      prize = prize - winGold;
      prize = prize > 0 ? 0 : prize;
    }

    prizePool.getPrize().getAndSet(prize);
    return shuiHuReward;
  }

  /**
   * 水机房间奖池图片.
   * 
   * @param seat 座位信息
   * @param prizePool 奖池
   * @return 奖励
   */
  private ShuiHuReward randomRoomPrizePoolIcons(ShuiHuSeat seat, RoomPrizePool prizePool) {
    ShuiHuReward shuiHuReward = null;

    // 房间奖池控制策略
    ControlStrategy strategy = prizePool.abledControlStrategy();
    if (strategy != null) {
      ShuiHuControl control = strategy.control(SHUIHU_CONTROL_TYPE);
      ShuiHuDifficulty shuiHuDifficulty = ShuiHuDifficulty.get(control.getDifficulty());
      // 图标奖励
      shuiHuReward = randomDiffcultyIcons(seat, shuiHuDifficulty);
    } else {
      // 图标奖励
      shuiHuReward = randomNormalShuiHuIcons(seat);
    }

    long winGold = shuiHuMgr.convertGold(seat.getTable().getRoom().getRoomDomain(),
        shuiHuReward.getWin() - seat.getLine() * seat.getBet());
    prizePool.getPrize().addAndGet(-winGold);

    return shuiHuReward;
  }

  /**
   * 随机筛子点数.
   * 
   * @param seat 座位.
   * @param betType 押押注类型，小于0:小,0:和,大于0:大.
   * @param betChips 押注筹码.
   * @return 3元祖,前2个元素为筛子点数，最后一个为奖励.
   */
  public Pair<Integer, Integer> randomDicePoints(ShuiHuSeat seat, int betType, long betChips) {
    /*
     * 个人奖池控制 .
     */
    PlayerPrizePool prizePool =
        playerPrizePoolMgr.prizePool(seat.getPlayerId(), Game.SHUI_HU_ZHUAN);
    if (prizePool != null && prizePool.getPrize().get() != 0) {
      return randomPlayerPrizePoolDicePoints(seat, prizePool, betType, betChips);
    }

    /*
     * 房间奖池控制 .
     */
    long roomId = seat.getTable().getRoom().getId();
    RoomPrizePool roomPrizePool =
        roomPrizePoolMgr.roomPrizePool(seat.getPlayerId(), Game.SHUI_HU_ZHUAN, roomId);
    if (roomPrizePool != null) {
      return randomRoomPrizePoolDicePoints(seat, roomPrizePool, betType, betChips);
    }

    // 正常概率图标
    return randomNormalDicePoints();
  }

  /**
   * 随机个人奖池骰子点数.
   * 
   * @param seat 座位信息.
   * @param prizePool 奖池.
   * @param betType 下注类型.
   * @param betChips 下注金币.
   * @return 3元祖,前2个元素为筛子点数，最后一个为骰子筹码奖励.
   */
  private Triplet<Integer, Integer, Long> randomPlayerPrizePoolDicePoints(ShuiHuSeat seat,
      PlayerPrizePool prizePool, int betType, long betChips) {
    // ShuiHuControl control = prizePool.control(SHUIHU_CONTROL_TYPE);
    boolean win = true;

    // if (betType != 0) { // 走大小的控制
    // win = RandCodeUtil.random(100) < control.getDaxiaoRatio();
    // } else { // 走和的控制
    // win = RandCodeUtil.random(100) < control.getHeRatio();
    // }
    long prize = prizePool.getPrize().get();

    Pair<Integer, Integer> resPonis = randomFixedDicePoints(betType, win);
    int p1 = resPonis.v1;
    int p2 = resPonis.v2;
    // 骰子游戏赢得的筹码
    long winChips = shuiHuMgr.calDiceGameChips(p1, p2, betType, betChips);
    long winGold =
        shuiHuMgr.convertGold(seat.getTable().getRoom().getRoomDomain(), winChips - betChips);

    if (prize > 0) {
      prize = prize - winGold;
      prize = prize < 0 ? 0 : prize;
    } else if (prize < 0) {
      prize = prize - winGold;
      prize = prize > 0 ? 0 : prize;
    }

    prizePool.getPrize().getAndSet(prize);
    return new Triplet<>(p1, p2, winChips);
  }

  /**
   * 随机房间奖池骰子点数.
   * 
   * @param seat 座位信息
   * @param prizePool 奖池
   * @param betType 押押注类型，小于0:小,0:和,大于0:大
   * @param betChips 下注金币
   * @return 3元祖,前2个元素为筛子点数，最后一个为骰子筹码奖励
   */
  private Triplet<Integer, Integer, Long> randomRoomPrizePoolDicePoints(ShuiHuSeat seat,
      RoomPrizePool prizePool, int betType, long betChips) {
    // 房间奖池控制策略
    ControlStrategy strategy = prizePool.abledControlStrategy();
    Pair<Integer, Integer> resPonis = null;

    if (strategy != null) {
      // ShuiHuControl control = strategy.control(SHUIHU_CONTROL_TYPE);
      boolean win = true;

      // if (betType != 0) { // 走大小的控制
      // win = RandCodeUtil.random(100) < control.getDaxiaoRatio();
      // } else { // 走和的控制
      // win = RandCodeUtil.random(100) < control.getHeRatio();
      // }
      resPonis = randomFixedDicePoints(betType, win);
    } else {
      resPonis = randomNormalDicePoints();
    }

    int p1 = resPonis.v1;
    int p2 = resPonis.v2;

    // 骰子游戏赢得的筹码
    long winChips = shuiHuMgr.calDiceGameChips(p1, p2, betType, betChips);
    long winGold =
        shuiHuMgr.convertGold(seat.getTable().getRoom().getRoomDomain(), winChips - betChips);
    prizePool.getPrize().addAndGet(-winGold);

    return new Triplet<>(resPonis.v1, resPonis.v2, winChips);
  }

  /**
   * 随机正常骰子点数.
   * 
   * @return 点数
   */
  private Pair<Integer, Integer> randomNormalDicePoints() {

    return new Pair<>(RandCodeUtil.random(1, 6), RandCodeUtil.random(1, 6));
  }

  /**
   * 随机确定类型的骰子点数.
   * 
   * @param betType 押押注类型，小于0:小,0:和,大于0:大
   * @param win 赢
   * @return 点数
   */
  private Pair<Integer, Integer> randomFixedDicePoints(int betType, boolean win) {
    int p1 = 0;
    int p2 = 0;

    for (;;) {
      p1 = RandCodeUtil.random(1, 6);
      p2 = RandCodeUtil.random(1, 6);
      int sum = p1 + p2;

      if (betType < 0 && win == sum < 7) {
        return new Pair<>(p1, p2);
      } else if (betType > 0 && win == sum > 7) {
        return new Pair<>(p1, p2);
      } else if (betType == 0 && win == (sum == 7)) {
        return new Pair<>(p1, p2);
      }
    }
  }

  /**
   * 小玛丽游戏.
   * 
   * @param seat 座位
   */
  public ResMessage doXiaoMaLiStart(ShuiHuSeat seat) {
    int insideIcon = 0;
    /*
     * 随机内部图标(4个),使用LinkedListMultimap方便计算 .
     */
    LinkedListMultimap<Integer, Integer> insideIcons = LinkedListMultimap.create();
    insideIcons.put(insideIcon = RandCodeUtil.random(1, 8), insideIcon);
    insideIcons.put(insideIcon = RandCodeUtil.random(1, 8), insideIcon);
    insideIcons.put(insideIcon = RandCodeUtil.random(1, 8), insideIcon);
    insideIcons.put(insideIcon = RandCodeUtil.random(1, 8), insideIcon);

    // 内圈图标kickOut
    kickOutInnerIcons(insideIcons, insideIcon);

    /*
     * 随机外部图标 .
     */
    // 外部图标
    int outsideIcon = 0;
    // 外部图标合计权重
    int totalWeight = bonusIconDic.getTotalWeight() + seat.getXiaoMaLiTotalWeightChange();
    // 随机数
    int rand = RandCodeUtil.random(totalWeight);
    int sum = 0;

    for (int i = 0; i < bonusIconDic.list().size(); i++) {
      ShuihuBonusIconDomain bonusIconDomain = bonusIconDic.list().get(i);
      // 权重变化
      Integer weightChange = seat.getXiaoMaLiWeightChangeMap().get(bonusIconDomain.getId());
      if (weightChange == null) {
        weightChange = 0;
        seat.getXiaoMaLiWeightChangeMap().put(bonusIconDomain.getId(), weightChange);
      }
      // 剩余的权重
      int leftWeight = bonusIconDomain.getWeight() + weightChange;
      if (leftWeight < 0) {
        leftWeight = 0;
      }
      sum += leftWeight;
      if (rand < sum) {
        outsideIcon = bonusIconDomain.getId();
        // 执行kickOut
        ShuihuBonusOuterKickOutDomain outerKickOutDomain =
            shuihuBonusOuterKickOutDic.get(outsideIcon);

        int kickOut = outerKickOutDomain.getKickOut();
        int kickOutMax = outerKickOutDomain.getKickOutMax();
        if (RandCodeUtil.random(kickOutMax) <= kickOut) {
          if (i < bonusIconDic.list().size() - 1) {
            outsideIcon = bonusIconDic.list().get(i + 1).getId();
          } else {
            outsideIcon = bonusIconDic.list().get(0).getId();
          }
        }
        break;
      }
    }

    // 增加/减少权重
    int totalChange = 0;
    for (int i = 0; i < bonusIconDic.list().size(); i++) {
      ShuihuBonusIconDomain bonusIconDomain = bonusIconDic.list().get(i);
      // 获取已经变化的权重
      Integer weightChange =
          seat.getXiaoMaLiWeightChangeMap().getOrDefault(bonusIconDomain.getId(), 0);
      // 图标剩余的权重
      int leftWeight =
          bonusIconDomain.getWeight() + weightChange + bonusIconDomain.getWeightChange();
      int change = 0;
      if (leftWeight < 0) {
        change -= bonusIconDomain.getWeight();
      } else {
        change = weightChange + bonusIconDomain.getWeightChange();
      }
      totalChange += change;
      seat.getXiaoMaLiWeightChangeMap().put(bonusIconDomain.getId(), change);
    }
    seat.setXiaoMaLiTotalWeightChange(totalChange);

    long winChips = 0;
    // 转到退出图标
    // if (outsideIcon == BONUS_EXIT_ICON) {
    // seat.bonus = 0;
    // msgMgr.sendXiaoMaLiStartMsg(seat, insideIcons.values(), outsideIcon, winChips);
    // } else {
    // seat.bonus--;
    // int multiple = 0;
    ResMessage result = null;
    if (outsideIcon == BONUS_EXIT_ICON) {
      seat.setBonus(seat.getBonus() - 1);
      result = msgMgr.resXiaoMaLiStartMsg(seat, insideIcons.values(), outsideIcon, winChips);
      // 每次bonus重置权重配置
      seat.setXiaoMaLiWeightChangeMap(new ConcurrentHashMap<Integer, Integer>());
      seat.setXiaoMaLiTotalWeightChange(0);
    } else {
      int multiple = 0;

      // 内部图标是否中奖
      if (insideIcons.keySet().size() == 1) {
        // 四连线
        ShuihuBonusInnerCfgDomain innerCfgDomain =
            shuihuBonusInnerCfgDic.get(BonusInnerCfgTypeConstant.FOUR_ICON);
        multiple += innerCfgDomain.getRate();
      } else if (insideIcons.keySet().size() == 2
          && (insideIcons.get(insideIcon).size() == 1 || insideIcons.get(insideIcon).size() == 3)) {
        // 三连线
        ShuihuBonusInnerCfgDomain innerCfgDomain =
            shuihuBonusInnerCfgDic.get(BonusInnerCfgTypeConstant.THREE_ICON);
        multiple += innerCfgDomain.getRate();
      }

      // 外面是否中奖
      if (insideIcons.keySet().contains(outsideIcon)) {
        multiple +=
            bonusIconDic.map().get(outsideIcon).getRate() * insideIcons.get(outsideIcon).size();
      }

      // win = (内部中奖 + 外部图标中奖) * 当前总押注 .
      winChips = multiple * seat.getBet() * seat.getLine();
      seat.setBillChips(seat.getBillChips() + winChips);
      result = msgMgr.resXiaoMaLiStartMsg(seat, insideIcons.values(), outsideIcon, winChips);
    }


    /*
     * 个人奖池控制 .
     */
    PlayerPrizePool prizePool =
        playerPrizePoolMgr.prizePool(seat.getPlayerId(), Game.SHUI_HU_ZHUAN);
    Long prize = 0L;
    long winGold = shuiHuMgr.convertGold(seat.getTable().getRoom().getRoomDomain(), winChips);
    if (prizePool != null && (prize = prizePool.getPrize().get()) != 0) {
      if (prize > 0) {
        prize = prize - winGold;
        prize = prize < 0 ? 0 : prize;
      } else if (prize < 0) {
        prize = prize - winGold;
        prize = prize > 0 ? 0 : prize;
      }
      prizePool.getPrize().getAndSet(prize);
    }

    /*
     * 房间奖池控制 .
     */
    long roomId = seat.getTable().getRoom().getId();
    RoomPrizePool roomPrizePool =
        roomPrizePoolMgr.roomPrizePool(seat.getPlayerId(), Game.SHUI_HU_ZHUAN, roomId);
    if (roomPrizePool != null) {
      roomPrizePool.getPrize().addAndGet(-winGold);
    }

    return result;
  }

  private void kickOutInnerIcons(LinkedListMultimap<Integer, Integer> insideIcons, int insideIcon) {
    int type = 0;
    int removeIcon = 0;
    if (insideIcons.keySet().size() == 1) {
      type = BonusInnerCfgTypeConstant.FOUR_ICON; // 图标四连线
      removeIcon = insideIcon;
    } else if (insideIcons.keySet().size() == 2) {

      if (insideIcons.get(insideIcon).size() == 1) {
        // 左三连线
        type = BonusInnerCfgTypeConstant.THREE_ICON; // 图标三连线
        Set<Integer> set = insideIcons.keySet();
        for (Iterator<Integer> iterator = set.iterator(); iterator.hasNext();) {
          int key = iterator.next();
          if (key != insideIcon) {
            removeIcon = key;
            break;
          }
        }
      } else if (insideIcons.get(insideIcon).size() == 3) {
        // 右三连线
        type = BonusInnerCfgTypeConstant.THREE_ICON; // 图标三连线
        removeIcon = insideIcon;
      }
    }

    if (type == BonusInnerCfgTypeConstant.FOUR_ICON
        || type == BonusInnerCfgTypeConstant.THREE_ICON) {
      // 获取内圈配置
      ShuihuBonusInnerCfgDomain innerCfgDomain = shuihuBonusInnerCfgDic.get(type);
      int kickOut = innerCfgDomain.getKickOut();
      int kickOutMax = innerCfgDomain.getKickOutMax();
      // kick-out
      if (RandCodeUtil.random(kickOutMax) <= kickOut) {
        insideIcons.remove(removeIcon, removeIcon); // 移除一个(连线中的任何一个图标)
        insideIcons.put(insideIcon = RandCodeUtil.random(1, 8), insideIcon);
      }
    }
  }

}
